package com.example.baozidemo.commons.mybatis;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.example.baozidemo.utils.Constant;
import com.example.baozidemo.utils.ConvertUtils;
import com.example.baozidemo.utils.PageData;

import java.io.Serializable;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collector;
import java.util.stream.Collectors;

/**
 * 基础方法类
 *
 * @author steed
 * @since 2020/11/11
 **/
public interface BaseService<T> extends IService<T> {

    /**
     * 筛选条件
     *
     * @param params map
     * @return QueryWrapper
     */
    QueryWrapper<T> queryWrapper(Map<String, Object> params);

    /**
     * 关联处理
     *
     * @param list   源数据
     * @param params 筛选条件
     */
    void handleList(List<T> list, Map<String, Object> params);

    default IPage<T> getPage(Map<String, Object> params, String defaultOrderField, Boolean isAsc) {
        // 分页参数
        long curPage = 1;
        long limit = 10;

        if (params.get(Constant.PAGE) != null) {
            curPage = Long.parseLong(params.get(Constant.PAGE).toString());
        }
        if (params.get(Constant.LIMIT) != null) {
            limit = Long.parseLong(params.get(Constant.LIMIT).toString());
        }

        // 分页对象
        Page<T> page = new Page<>(curPage, limit);

        // 分页参数
        params.put(Constant.PAGE, page);

        // 排序字段
        String orderField = (String) params.get(Constant.ORDER_FIELD);
        String order = (String) params.get(Constant.ORDER);

        // 前端字段排序
        if (StringUtils.isNotBlank(orderField) && StringUtils.isNotBlank(order)) {
            if (Constant.ASC.equalsIgnoreCase(order)) {
                return page.addOrder(OrderItem.asc(orderField));
            } else {
                return page.addOrder(OrderItem.desc(orderField));
            }
        }

        // 没有排序字段，则不排序
        if (StringUtils.isBlank(defaultOrderField)) {
            return page;
        }

        // 默认排序
        if (isAsc) {
            page.addOrder(OrderItem.asc(defaultOrderField));
        } else {
            page.addOrder(OrderItem.desc(defaultOrderField));
        }

        return page;
    }

    default <E> PageData<E> queryPage(Map<String, Object> params, Class<E> target) {
        return new PageData<>(this.queryPage(params), target);
    }

    default IPage<T> queryPage(Map<String, Object> params) {
        return this.queryPage(params, true);
    }

    default IPage<T> queryPage(Map<String, Object> params, Boolean isHandle) {
        IPage<T> page = this.page(getPage(params, "", false), this.queryWrapper(params));
        if (isHandle) {
            this.handleList(page.getRecords(), params);
        }
        return page;
    }

    default List<T> queryList(Collection<? extends Serializable> idList) {
        List<T> list = this.listByIds(idList);
        this.handleList(list, new HashMap<>());
        return list;
    }

    default List<T> queryList(Map<String, Object> params, Boolean isHandle) {
        List<T> list = this.list(this.queryWrapper(params));
        if (isHandle) {
            this.handleList(list, params);
        }
        return list;
    }

    default <E> List<E> queryList(Map<String, Object> params, Boolean isHandle, Class<E> target) {
        List<T> list = this.list(this.queryWrapper(params));
        if (isHandle) {
            this.handleList(list, params);
        }
        return ConvertUtils.sourceToTarget(list, target);
    }

    default List<T> queryList(Wrapper<T> queryWrapper, Boolean isHandle) {
        List<T> list = this.list(queryWrapper);
        if (isHandle) {
            this.handleList(list, new HashMap<>());
        }
        return list;
    }

    default <V> Map<V, T> queryMap(Collection<? extends Serializable> idList, Function<? super T, V> mapper, Boolean isHandle) {
        List<T> list = this.listByIds(idList);
        if (isHandle) {
            this.handleList(list, new HashMap<>());
        }
        return list.stream().collect(Collectors.toMap(mapper, Function.identity()));
    }

    default <V, U> Map<V, U> queryMap(Collection<? extends Serializable> idList, Function<? super T, V> keyMapper, Function<? super T, U> valueMapper, Boolean isHandle) {
        List<T> list = this.listByIds(idList);
        if (isHandle) {
            this.handleList(list, new HashMap<>());
        }
        return list.stream().collect(Collectors.toMap(keyMapper, valueMapper));
    }

    default <V> Map<V, T> queryMap(Wrapper<T> queryWrapper, Function<? super T, V> mapper, Boolean isHandle) {
        List<T> list = this.list(queryWrapper);
        if (isHandle) {
            this.handleList(list, new HashMap<>());
        }
        return list.stream().collect(Collectors.toMap(mapper, Function.identity()));
    }

    default <V, U> Map<V, U> queryMap(Wrapper<T> queryWrapper, Function<? super T, V> keyMapper, Function<? super T, U> valueMapper, Boolean isHandle) {
        List<T> list = this.list(queryWrapper);
        if (isHandle) {
            this.handleList(list, new HashMap<>());
        }
        return list.stream().collect(Collectors.toMap(keyMapper, valueMapper));
    }

    default <V> Map<V, List<T>> queryListMap(Collection<? extends Serializable> idList, Function<? super T, V> mapper, Boolean isHandle) {
        List<T> list = this.listByIds(idList);
        if (isHandle) {
            this.handleList(list, new HashMap<>());
        }
        return list.stream().collect(Collectors.groupingBy(mapper, LinkedHashMap::new, Collectors.toList()));
    }

    default <V> Map<V, List<T>> queryListMap(Map<String, Object> params, Function<? super T, V> mapper, Boolean isHandle) {
        List<T> list = this.list(this.queryWrapper(params));
        if (isHandle) {
            this.handleList(list, new HashMap<>());
        }
        return list.stream().collect(Collectors.groupingBy(mapper, LinkedHashMap::new, Collectors.toList()));
    }

    default <V> Map<V, List<T>> queryListMap(Wrapper<T> queryWrapper, Function<? super T, V> mapper, Boolean isHandle) {
        List<T> list = this.list(queryWrapper);
        if (isHandle) {
            this.handleList(list, new HashMap<>());
        }
        return list.stream().collect(Collectors.groupingBy(mapper, LinkedHashMap::new, Collectors.toList()));
    }

    default <V, A, R> Map<V, R> queryListMap(Collection<? extends Serializable> idList, Function<? super T, V> mapper, Collector<? super T, A, R> collector, Boolean isHandle) {
        List<T> list = this.listByIds(idList);
        if (isHandle) {
            this.handleList(list, new HashMap<>());
        }
        return list.stream().collect(Collectors.groupingBy(mapper, LinkedHashMap::new, collector));
    }

    default <V, A, R> Map<V, R> queryListMap(Map<String, Object> params, Function<? super T, V> mapper, Collector<? super T, A, R> collector, Boolean isHandle) {
        List<T> list = this.list(this.queryWrapper(params));
        if (isHandle) {
            this.handleList(list, new HashMap<>());
        }
        return list.stream().collect(Collectors.groupingBy(mapper, LinkedHashMap::new, collector));
    }

    default <V, A, R> Map<V, R> queryListMap(Wrapper<T> queryWrapper, Function<? super T, V> mapper, Collector<? super T, A, R> collector, Boolean isHandle) {
        List<T> list = this.list(queryWrapper);
        if (isHandle) {
            this.handleList(list, new HashMap<>());
        }
        return list.stream().collect(Collectors.groupingBy(mapper, LinkedHashMap::new, collector));
    }

    default <V> List<V> queryValueList(Collection<? extends Serializable> idList, Function<? super T, V> mapper) {
        return this.listByIds(idList).stream().filter(Objects::nonNull).map(mapper).distinct().collect(Collectors.toList());
    }

    default <V> List<V> queryValueList(Map<String, Object> params, Function<? super T, V> mapper) {
        return this.list(this.queryWrapper(params)).stream().filter(Objects::nonNull).map(mapper).distinct().collect(Collectors.toList());
    }

    default <V> List<V> queryValueList(Wrapper<T> queryWrapper, Function<? super T, V> mapper) {
        return this.list(queryWrapper).stream().filter(Objects::nonNull).map(mapper).distinct().collect(Collectors.toList());
    }
}
